package com.gblfy.lyrabbitmq.confirms;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.stereotype.Component;

/**
 * Confirm 消息确认机制
 * 消息发送成功和失败都会记录
 *
 * @author gblfy
 * @Date 2021-09-28 9:59
 */
@Component("confirmCallback")
public class ConfirmCallBackListener implements RabbitTemplate.ConfirmCallback {

    //日志输出
    private final static Logger log = LoggerFactory.getLogger(ConfirmCallBackListener.class);

    /**
     * 生产者消息发送成功与失败确认机制
     * <p>
     * 1. ack
     *      true : 标志生产者将消息发出成功
     *      false: 标志生产者将消息发出失败
     * 2. ack :true 意味着消息发送成功 有2种场景
     *      第一种：生产者将消息成功发送到指定队列中，等待消费者消费消息
     *      第两种：生产者将消息发送成功，但是，由于无法路由到指定的消息
     *             队列，这种场景的消息，会被return机制监听到，后续进行补偿机制，做消息补发处理
     * </p>
     *
     * @param correlationData 队列消息的唯一标识ID，消息做补偿机制会用到
     * @param ack             ack 消息是否发送成功的标识
     * @param cause           消息发送失败的原因
     */
    @Override
    public void confirm(CorrelationData correlationData, boolean ack, String cause) {

        log.info("消息队列标识ID: {}", correlationData.getId());

        /**
         *对消息发送成功/失败状态做不同的处理
         * 1. 第一种场景 发送消息成功
         *     1>发送消息成功，交换机路由队列成功
         *     2>发送消息成功，交换机路由队列不成功
         * 2. 发送消息失败
         */
        if (ack) {
            log.info("发送消息成功: {}", ack);
        } else {
            log.info("发送消息失败: {}", ack);
        }
    }
}
/**
 * ！ack 场景结果示例:
 * <p>
 * correlationData: CorrelationData [id=a37285dc-5dd6-4e22-8cc4-5c0fbf67b568]
 * ack: false
 * 异常处理....
 * 消息: CorrelationData [id=a37285dc-5dd6-4e22-8cc4-5c0fbf67b568]，
 * nack，失败原因是：channel error;
 * protocol method: #method<channel.close>(reply-code=404, reply-text=NOT_FOUND - no exchange 'FIS-TRACE-COMMON-EXCHANGE' in vhost '/admin',
 * class-id=60, method-id=40)
 */

